﻿// //  ********************************************************************************
// //  Copyright (C) 2016 Sebastian Kenter. All rights reserved.
// // 
// //  Name    : PhotonServerProject | PhotonServerFramework | ServerPeerRegistry.cs
// //  Created : 2016 - 03 - 21 16:31
// //  Modified: 2016 - 04 - 18 09:38
// //  ********************************************************************************

using System;
using System.Collections.Generic;
using System.Linq;
using ExitGames.Logging;
using NHibernate;
using PhotonServerCommon.Entities.Domain;
using PhotonServerFramework.Implementation.Database;
using PhotonServerFramework.Interfaces.Server;

namespace PhotonServerFramework.Implementation.Server
{
    public class ServerPeerRegistry : IServerPeerRegistry
    {
        public ILogger Logger { get; }
        private readonly Dictionary<Guid, IServerPeer> _serverPeers = new Dictionary<Guid, IServerPeer>();

        public ServerPeerRegistry(ILogger logger)
        {
            Logger = logger;
        }

        public bool RegisterServerPeer(IServerPeer serverPeer)
        {
            if (_serverPeers.ContainsKey(serverPeer.ServerPeerId))
            {
                Logger.ErrorFormat("Cannot register the same server twice (Guid: {0})", serverPeer.ServerPeerId);
                return false;
            }

            _serverPeers.Add(serverPeer.ServerPeerId, serverPeer);
            Logger.InfoFormat("Registered server peer with id={0} on server={1}", serverPeer.ServerPeerId,
                serverPeer.ServerPeerData.ApplicationId);

            return true;
        }

        public bool UnregisterServerPeer(Guid peerId)
        {
            if (!_serverPeers.ContainsKey(peerId))
            {
                Logger.ErrorFormat("Cannot unregister cause server not registered (Guid: {0})", peerId);
                return false;
            }

            _serverPeers.Remove(peerId);
            Logger.InfoFormat("Unregistered server peer with id = {0}", peerId);
            return true;
        }

        public IServerPeer GetServerPeerById(Guid peerId)
        {
            return _serverPeers.FirstOrDefault(c => c.Key == peerId).Value;
        }

        public Dictionary<Guid, IServerPeer> GetServerPeers()
        {
            return _serverPeers;
        }

        public void UnregisterServerPeers(Guid serverId)
        {
            IList<ServerPeerT> servers = null;

            using (ISession session = SessionManager.OpenSession())
            {
                using (ITransaction transaction = session.BeginTransaction())
                {
                    try
                    {
                        servers =
                            session.QueryOver<ServerPeerT>()
                                .Where(c => c.LocalServerId == serverId.ToString())
                                .List<ServerPeerT>();
                        transaction.Commit();
                    }
                    catch (Exception ex)
                    {
                        Logger.ErrorFormat("Operation failed with: {0}", ex.Message);
                        transaction.Rollback();
                    }
                }

                session.Close();
            }

            if (servers == null) return;

            foreach (ServerPeerT server in servers)
            {
                UnregisterServerPeer(Guid.Parse(server.LocalPeerId));
                using (ISession session = SessionManager.OpenSession())
                {
                    using (ITransaction transaction = session.BeginTransaction())
                    {
                        try
                        {
                            session.Delete(server);
                            transaction.Commit();
                        }
                        catch (Exception ex)
                        {
                            Logger.ErrorFormat("Operation failed with: {0}", ex.Message);
                            transaction.Rollback();
                        }
                    }

                    session.Close();
                }
            }
        }
    }
}
